package main

import (
	"errors"
	"fmt"
	"math"
	"math/rand"
	"sync"
	"test/pid"
	"time"
)

// PID 控制器增强版结构体
type PID struct {
	Kp           float64    // 比例系数
	Ki           float64    // 积分系数
	Kd           float64    // 微分系数
	outputLimits [2]float64 // 输出限幅 [min, max]
	integralLim  [2]float64 // 积分限幅 [min, max]
	deadZone     float64    // 死区范围
	prevError    float64    // 前次误差
	prevMeasured float64    // 前次测量值
	integral     float64    // 积分累积值
	lastTime     time.Time  // 上次计算时间
	mu           sync.Mutex // 线程安全锁
}

// NewPID 创建PID控制器实例
func NewPID(kp, ki, kd float64) *PID {
	return &PID{
		Kp:           kp,
		Ki:           ki,
		Kd:           kd,
		outputLimits: [2]float64{math.Inf(-1), math.Inf(1)},
		integralLim:  [2]float64{math.Inf(-1), math.Inf(1)},
		lastTime:     time.Now(),
	}
}

// SetOutputLimits 设置输出限幅
func (pid *PID) SetOutputLimits(min, max float64) error {
	if min >= max {
		return errors.New("invalid limits")
	}
	pid.outputLimits = [2]float64{min, max}
	return nil
}

// SetIntegralLimits 设置积分限幅
func (pid *PID) SetIntegralLimits(min, max float64) error {
	if min >= max {
		return errors.New("invalid limits")
	}
	pid.integralLim = [2]float64{min, max}
	return nil
}

// SetDeadZone 设置死区范围
func (pid *PID) SetDeadZone(value float64) {
	pid.deadZone = math.Abs(value)
}

// Reset 重置控制器状态
func (pid *PID) Reset() {
	pid.mu.Lock()
	defer pid.mu.Unlock()

	pid.prevError = 0
	pid.integral = 0
	pid.lastTime = time.Now()
}

// Compute 增强版PID计算
func (pid *PID) Compute(setpoint, measured float64) (float64, error) {
	pid.mu.Lock()
	defer pid.mu.Unlock()

	// 计算时间差
	now := time.Now()
	dt := now.Sub(pid.lastTime).Seconds()
	if dt <= 0 {
		return 0, errors.New("invalid time delta")
	}
	pid.lastTime = now

	// 计算误差项
	error := setpoint - measured

	// 死区处理
	if math.Abs(error) <= pid.deadZone {
		error = 0
	}

	// 比例项
	pTerm := pid.Kp * error

	// 积分项(带限幅)
	pid.integral += error * dt
	pid.integral = math.Max(pid.integralLim[0], math.Min(pid.integralLim[1], pid.integral))
	iTerm := pid.Ki * pid.integral

	// 微分项(采用测量值微分避免设定值突变)
	dTerm := -pid.Kd * (measured - pid.prevMeasured) / dt

	// 计算输出
	output := pTerm + iTerm + dTerm

	// 保存状态
	pid.prevError = error
	pid.prevMeasured = measured

	// 输出限幅
	return math.Max(pid.outputLimits[0], math.Min(pid.outputLimits[1], output)), nil
}

// 示例使用
func main1() {
	// 创建PID控制器
	pid := NewPID(2.5, 0.8, 0.1)

	// 配置参数
	pid.SetOutputLimits(0, 100)    // 输出范围0-100%
	pid.SetIntegralLimits(-10, 10) // 防止积分饱和
	pid.SetDeadZone(0.5)           // 设置死区

	// 模拟控制循环
	var (
		setpoint  = 50.0 // 目标温度
		measured  = 25.0 // 当前温度
		heaterPct = 0.0  // 加热功率
	)

	for i := 0; i < 10; i++ {
		time.Sleep(time.Second)
		output, _ := pid.Compute(setpoint, measured)
		heaterPct = output
		// 更新系统状态(示例)
		measured += heaterPct*0.3 - 1 // 简单热力学模型
		fmt.Println("headter:", heaterPct, "measured:", measured)
	}
}

func main() {
	// 负荷跟踪场景参数
	pida := pid.NewPID(0.8, 0.05, 0.1)
	pida.SetDeadZone(0.5)         // 设置0.5kW死区
	pida.SetOutputLimits(-90, 90) // 发电机出力限制

	var (
		actualLoad   float64 = 50 // 当前负荷(kW)
		targetLoad   float64 = 60 // 目标负荷(kW)
		generatorOut float64 = 50 // 发电机当前出力
	)

	// 模拟控制循环
	for i := 0; i < 30; i++ {
		adjustment := pida.Compute(targetLoad, actualLoad)
		generatorOut += adjustment
		actualLoad = simulateLoadChange(generatorOut)

		fmt.Printf("Cycle %d: Target=%.1f Actual=%.1f Adjustment=%.2f  generatorOut=%.2f\n",
			i+1, targetLoad, actualLoad, adjustment, generatorOut)
		time.Sleep(1 * time.Second)
	}
}

// 模拟负荷变化（含±10%随机波动）
func simulateLoadChange(powerOut float64) float64 {
	return powerOut * (0.9 + 0.2*rand.Float64())
}
